/*
 
(c) 2008 by Sławek Kruczek
slav.mir@gmail.com
 

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/


package analytics.util;

import java.util.Iterator;
import java.util.NoSuchElementException;


public class TokenExtractor implements Iterator<String> {
    
    private String expression;
    
    private int position = 0;
    private String nextToken = null;
    
    

    
    public TokenExtractor(String expression) {
        this.expression = expression;     
        nextToken = getNextToken();
    }
    
    
    private String getNextToken() {
        // skipping whitespace
        while(position < expression.length() && Character.isWhitespace(expression.charAt(position)))
            position++;
        
        if(position >= expression.length())
            return null;
        
        
        int oldPosition = position;
        
        // Single character tokens are cases in the switch statement; longer ones are dealt with in the default: section
        switch(expression.charAt(position)) {
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
            case '(':
            case ')':
            case ',':
            case 'x':
            case 'y':
                position++;
                break;
           
            default:
                // Numerical constants start with a digit and can contain a dot.
                // NOTE: numbers are not checked for validity at this point or anywhere inside this iterator.
                if(Character.isDigit(expression.charAt(position))) {         
                    do {
                        position++;
                    } while(position < expression.length() && (
                            Character.isDigit(expression.charAt(position)) || expression.charAt(position) == '.'));        
                }
               
                // Function and constant names start with a letter and can contain underscores and digits.
                else if(Character.isLetter(expression.charAt(position))) {     
                    do {
                        position++;
                    } while(position < expression.length() && (
                            Character.isLetter(expression.charAt(position)) ||
                            Character.isDigit(expression.charAt(position)) ||
                            expression.charAt(position) == '_'));
                }
        }
        
        if(oldPosition == position) {
            throw new IllegalArgumentException("Unknown symbol: " + expression.substring(oldPosition, oldPosition + 1));
        }
        
        return expression.substring(oldPosition, position);
    }
    
    
    // Iterator interface implementation
    public String next() {
        if(!hasNext())
            throw new NoSuchElementException();
        
        String token = nextToken;
        nextToken = getNextToken();
        
        return token;
    }
    
    public boolean hasNext() {
        return nextToken != null;
    }

    public void remove() {
        throw new UnsupportedOperationException("Will never be supported.");
    }

}
